package my.mark.mybaibaoxiang.twotiger.contract.utils;

import com.itextpdf.awt.geom.Rectangle2D;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import com.itextpdf.text.pdf.PdfSignatureAppearance.RenderingMode;
import com.itextpdf.text.pdf.parser.ImageRenderInfo;
import com.itextpdf.text.pdf.parser.PdfReaderContentParser;
import com.itextpdf.text.pdf.parser.RenderListener;
import com.itextpdf.text.pdf.parser.TextRenderInfo;
import com.itextpdf.text.pdf.security.*;
import com.itextpdf.text.pdf.security.MakeSignature.CryptoStandard;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import com.jfinal.log.Logger;
import com.twotiger.system.filestoreage.FileStoreageFactory;
import com.twotiger.util.Base64;
import com.twotiger.util.ConfigUtil;
import com.twotiger.util.PathUtil;
import freemarker.cache.ClassTemplateLoader;
import freemarker.cache.StringTemplateLoader;
import freemarker.cache.TemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.io.*;
import java.net.URL;
import java.nio.charset.Charset;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;

/**
 * 
 * @Description: Pdf 导出工具 
 * 通过freemarker 模板引擎将动态数据html化
 * 通过itext 将html进行转pdf操作
 * @Author hansc
 * @Date 2014年9月24日 上午9:24:28
 */
public class ContractPdfKit {

    private static final Logger log = Logger.getLogger(ContractPdfKit.class);
    
    private static boolean ok = true;

    private static Rectangle2D boundingRectange = null;
    
    private static boolean findSiteOk = false;

    public ContractPdfKit() {
        Security.addProvider(new BouncyCastleProvider());
    }
    
    /**
     * 导出pdf
     * 
     * @param templateView-freemarker模板相对路径
     * @param os-输出流
     * @param model-模板所需要的数据
     * @throws Exception
     */
    //public static InputStream customerExport(InputStream temp, CustomerCert user, String flag, int site) throws Exception {
    public static InputStream customerExport(InputStream temp, String flag, int site) throws Exception {
        ByteArrayOutputStream tempArrayOutputStream = new ByteArrayOutputStream();
        //final String imagePath = user.get("picturePath").toString();
        final String imagePath = "src\\main\\java\\my\\mark\\mybaibaoxiang\\twotiger\\contract\\2020\\11\\26\\1606376901271_C314AEE7FA9DE00F040BEBE86E4F0C19.png";

        String pwd = "cfca1234";
        final String finalFlag = flag;
        try {
            //InputStream userPfx = new ByteArrayInputStream(Base64.decode(user.get("pfxPath").toString()));
            InputStream userPfx = new ByteArrayInputStream(Base64.decode("5LiA5Liq6K+B5Lmm"));
            //开始签名
            Security.addProvider(new BouncyCastleProvider());
            KeyStore ks = KeyStore.getInstance("pkcs12");
            ks.load(userPfx, pwd.toCharArray());
            String alias = ks.aliases().nextElement();
            PrivateKey key = (PrivateKey) ks.getKey(alias, pwd.toCharArray());
            Certificate[] chain = ks.getCertificateChain(alias);

            PdfReader reader = new PdfReader(temp); //源文件

            final PdfStamper stamper = PdfStamper.createSignature(reader, tempArrayOutputStream,
                '\0', null, true);
            
            //获取最后一页
            
            final int total = reader.getNumberOfPages();
            int realPage = 0;
            
            //先打水印，否则会导致之前的签章无效
            if (site == 0) {    //生成合同只有第一次签章前生成水印
//              ok = false;       //先注掉,因为多次生成合同,第二次后 ok=false 合同不会再生成水印
                PdfContentByte content;
                URL logoPath = FileStoreageFactory.getDefaultContract().getImage(
                    "data/contract/logo/logo.png");
                Image image = Image.getInstance(logoPath);
                // 循环对每页插入水印
                for (int i = 1; i < total + 1; i++) {
                    // 水印的起始
                    content = stamper.getUnderContent(i);
                    content.beginText();
                    // 开始写入水印
                    for (int k = 0; k < 5; k++) {
                        for (int j = 0; j < 4; j++) {
                            image.setAbsolutePosition(150 * j, 170 * k);
                            content.addImage(image);
                        }
                    }
                    content.endText();
                }
            }
            
            //获取页面内容
            PdfReaderContentParser pdfReaderContentParser = new PdfReaderContentParser(reader);
            //兼容从第一页查找
            int totalAll = total;
            if(total == 1){
                totalAll = 2;
            }
            for (int i = totalAll - 1; i <= total; i++) {
                pdfReaderContentParser.processContent(i, new RenderListener() {
                    @Override
                    public void renderText(TextRenderInfo textRenderInfo) {
                        String text = textRenderInfo.getText();
                        if (text.contains(finalFlag)) {
                            boundingRectange = textRenderInfo.getBaseline().getBoundingRectange();
                            findSiteOk = true;
                        }
                    }

                    @Override
                    public void beginTextBlock() {
                    }

                    @Override
                    public void endTextBlock() {
                    }

                    @Override
                    public void renderImage(ImageRenderInfo arg0) {
                    }

                });
                if(findSiteOk){
                    findSiteOk = false;
                    realPage = i;
                    break;
                }
            }

            // appearance
            PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
            appearance.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED);
            appearance.setVisibleSignature(new Rectangle(
                (float) (boundingRectange.getX() + boundingRectange.getWidth()),
                (float) (boundingRectange.getY() - 15),
                (float) (boundingRectange.getX() + boundingRectange.getWidth() + 70),
                (float) (boundingRectange.getY() + 35)), realPage, "Signature" + site);
            URL url = FileStoreageFactory.getDefaultContract().getImage(
                imagePath.substring(1, imagePath.length()));
            Image image = Image.getInstance(url);
            appearance.setSignatureGraphic(image);
            appearance.setCertificationLevel(PdfSignatureAppearance.NOT_CERTIFIED);
            appearance.setRenderingMode(RenderingMode.GRAPHIC);
            // signature
            ExternalSignature es = new PrivateKeySignature(key, "SHA-256", "BC");
            ExternalDigest digest = new BouncyCastleDigest();
            // end:
            MakeSignature.signDetached(appearance, digest, es, chain, null, null, null, 0,
                CryptoStandard.CMS);
        } catch (Exception e) {
            //log.error("客户pdf签章失败 customerId["+ user.get("customerId") +"]", e);
        }
        return new ByteArrayInputStream(tempArrayOutputStream.toByteArray());
    }

    /**
     * 导出pdf
     * 
     * @param templateView-freemarker模板相对路径
     * @param os-输出流
     * @param model-模板所需要的数据
     * @throws Exception
     */
    //public static InputStream companyExport(InputStream temp, CompanyCert company, String flag, int site) throws Exception {
    public static InputStream companyExport(InputStream temp, String flag, int site) throws Exception {
        ByteArrayOutputStream tempArrayOutputStream = new ByteArrayOutputStream();
        //final String imagePath = company.get("picturePath").toString();
        final String imagePath = "src\\main\\java\\my\\mark\\mybaibaoxiang\\twotiger\\contract\\2020\\11\\26\\1606376901271_C314AEE7FA9DE00F040BEBE86E4F0C19.png";


        String pwd = "cfca1234";
        final String finalFlag = flag;
        try {
            //InputStream userPfx = new ByteArrayInputStream(Base64.decode(company.get("pfxPath").toString()));
            InputStream userPfx = new ByteArrayInputStream(Base64.decode("5Lik5Liq6K+B5Lmm"));
            //开始签名
            Security.addProvider(new BouncyCastleProvider());
            KeyStore ks = KeyStore.getInstance("pkcs12");
            ks.load(userPfx, pwd.toCharArray());
            String alias = ks.aliases().nextElement();
            PrivateKey key = (PrivateKey) ks.getKey(alias, pwd.toCharArray());
            Certificate[] chain = ks.getCertificateChain(alias);

            PdfReader reader = new PdfReader(temp); //源文件

            final PdfStamper stamper = PdfStamper.createSignature(reader, tempArrayOutputStream,
                '\0', null, true);
            //获取最后一页
            final int total = reader.getNumberOfPages();
            int realPage = 0;
            //获取页面内容
            PdfReaderContentParser pdfReaderContentParser = new PdfReaderContentParser(reader);
            int totalAll = total;
            if(total == 1){
                totalAll = 2;
            }
            for (int i = totalAll - 1; i <= total; i++) {
                pdfReaderContentParser.processContent(i, new RenderListener() {
                    @Override
                    public void renderText(TextRenderInfo textRenderInfo) {
                        String text = textRenderInfo.getText();
                        if (text.contains(finalFlag)) {
                            boundingRectange = textRenderInfo.getBaseline().getBoundingRectange();
                            findSiteOk = true;
                        }
                    }

                    @Override
                    public void beginTextBlock() {
                    }

                    @Override
                    public void endTextBlock() {
                    }

                    @Override
                    public void renderImage(ImageRenderInfo arg0) {
                    }

                });
                if(findSiteOk){
                    findSiteOk = false;
                    realPage = i;
                    break;
                }
            }

            // appearance
            PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
            appearance.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED);
            appearance.setVisibleSignature(new Rectangle(
                (float) (boundingRectange.getX() + boundingRectange.getWidth() + 10),
                (float) (boundingRectange.getY() - 60),
                (float) (boundingRectange.getX() + boundingRectange.getWidth() + 100),
                (float) (boundingRectange.getY() + 40)), realPage, "Signature" + site);
            URL url = FileStoreageFactory.getDefaultContract().getImage(
                imagePath.substring(1, imagePath.length()));
            Image image = Image.getInstance(url);
            appearance.setSignatureGraphic(image);
            appearance.setCertificationLevel(PdfSignatureAppearance.NOT_CERTIFIED);
            appearance.setRenderingMode(RenderingMode.GRAPHIC);
            // signature
            ExternalSignature es = new PrivateKeySignature(key, "SHA-256", "BC");
            ExternalDigest digest = new BouncyCastleDigest();
            // end:
            MakeSignature.signDetached(appearance, digest, es, chain, null, null, null, 0,
                CryptoStandard.CMS);
        } catch (Exception e) {
            //log.error("企业pdf签章失败 companyId["+ company.get("companyId") +"]", e);
        }
        return new ByteArrayInputStream(tempArrayOutputStream.toByteArray());
    }

    /**
     * 填充合同内容
     * @param view "ht_pc_bond_stock.ftl",
     * @param model 要填充的数据
     * @return 返回临时pdf文件的地址
     * @throws Exception
     */
    public static String fillPDFData(String view, Object model) throws Exception {
        // 下载路径（临时文件夹路径）
        String path = "src\\main\\java\\my\\mark\\mybaibaoxiang\\twotiger\\contract";
        File pathFile = new File(path);
        if (!pathFile.exists())
            pathFile.mkdirs();
        //临时文件全路径名
        String temp = path + File.separator + System.currentTimeMillis()
                      + Thread.currentThread().getId() + ".pdf";
        try {
            //生成临时文件
            FileOutputStream tempOs = new FileOutputStream(temp);
            Configuration cfg = new Configuration();

            //============================读取本地文本文件============================
            TemplateLoader fileLoader = new ClassTemplateLoader(ContractPdfKit.class, "/" + "template");
            cfg.setTemplateLoader(fileLoader);
            //获取模板（template）  
            Template template = cfg.getTemplate(view, "UTF-8");

            //=============================直接取文本字符串，即从数据库读取模板内容===========================
            /*String templateContent="<p>测试富文本编辑:${aaa!}     再取一个：${bbb}</p><p>&nbsp; &nbsp; &nbsp; 换行一段</p><p>&nbsp;</p><h1><strong>五、</strong><strong>工作推进建议：</strong></h1><p>集团金融与协同运营是一个体系工程，需要分阶段推进，从易到难，从基础搭建逐步进入核心建设，从管理职能逐步过渡到运营职能。</p><p>建议分为三个阶段，各阶段工作如下图所示。</p><p>";
            StringTemplateLoader stringLoader = new StringTemplateLoader();
            stringLoader.putTemplate("myTemplate",templateContent);
            cfg.setTemplateLoader(stringLoader);
            Template template = cfg.getTemplate("myTemplate","utf-8");*/


                //========================================================

            StringWriter result = new StringWriter();
            template.setEncoding("UTF-8");
            template.process(model, result);
            String htmlData = result.toString();
            Document document = new Document();
            PdfWriter writer = PdfWriter.getInstance(document, tempOs);
            document.open();
            XMLWorkerHelper.getInstance().parseXHtml(writer, document,
                new ByteArrayInputStream(htmlData.getBytes()), null, Charset.forName("UTF-8"),
                new FontProvider() {

                    @Override
                    public boolean isRegistered(String fontname) {
                        return true;
                    }

                    @Override
                    public Font getFont(String fontname, String encoding, boolean embedded,
                                        float size, int style, BaseColor color) {
                        BaseFont bf = null;
                        try {
                            bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H",
                                BaseFont.NOT_EMBEDDED);
                        } catch (Exception e) {
                            log.error("字体构建失败", e);
                        }
                        Font font = new Font(bf, size, style, color);
                        font.setColor(color);
                        return font;
                    }
                });
            document.close();
        } catch (Exception e) {
            log.error("pdf签章内容填充失败", e);
        }
        return temp;
    }

}
